﻿//-----------------------------------------------------------------------
// <copyright file="SystemFolders.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings
using System;
using System.Security.Principal;
using System.Text;
using FastNET.CleanAct.Client.Win32.Unmanaged;

#endregion

namespace FastNET.CleanAct.Client.Win32
{
    /// <summary>
    /// System Folder Retrieval Utility class
    /// </summary>
    public static class SystemFolders
    {
        #region Public Retrieval Calls

        /// <summary>
        /// Retrieves a user folder path provided the ID of the folder and whether or not to retrieve the default path
        /// </summary>
        /// <param name="user">User to retrieve the folder from</param>
        /// <param name="folderType">KnownCommonFolderType with the folder to retrieve</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns></returns>
        public static string RetrieveUserFolderPath(WindowsIdentity user, KnownUserFolderType folderType, bool defaultFolder)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            // Everything newer starting with Vista is the new method
            return Environment.OSVersion.Version.Major > 6
                       ? GetUserVistaStyleFolder(user, folderType, defaultFolder)
                       : GetUserXPStyleFolder(user, folderType, defaultFolder);
        }

        /// <summary>
        /// Retrieves a default user folder path provided the ID of the folder and whether or not to retrieve the default path
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType with the folder to retrieve</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns></returns>
        public static string RetrieveDefaultUserFolderPath(KnownUserFolderType folderType, bool defaultFolder)
        {

            // Everything newer starting with Vista is the new method
            return Environment.OSVersion.Version.Major > 6
                       ? GetUserVistaStyleFolder(null, folderType, defaultFolder)
                       : GetUserXPStyleFolder(null, folderType, defaultFolder);
        }

        /// <summary>
        /// Retrieves a current user folder path provided the ID of the folder and whether or not to retrieve the default path
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType with the folder to retrieve</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns></returns>
        public static string RetrieveCurrentUserFolderPath(KnownUserFolderType folderType, bool defaultFolder)
        {
            // Everything newer starting with Vista is the new method
            return Environment.OSVersion.Version.Major > 6
                       ? GetUserVistaStyleFolder(WindowsIdentity.GetCurrent(), folderType, defaultFolder)
                       : GetUserXPStyleFolder(WindowsIdentity.GetCurrent(), folderType, defaultFolder);
        }

        /// <summary>
        /// Retrieves a common system folder path provided the ID of the folder and whether or not to retrieve the default path
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType with the folder to retrieve</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns></returns>
        public static string RetrieveCommonFolderPath(KnownCommonFolderType folderType, bool defaultFolder)
        {
            // Everything newer starting with Vista is the new method
            return Environment.OSVersion.Version.Major > 6
                       ? GetCommonVistaStyleFolder(folderType, defaultFolder)
                       : GetCommonXPStyleFolder(folderType, defaultFolder);
        }

        #endregion

        #region Common Folder Calls

        /// <summary>
        /// Retrieves the folder path knowing a folder type and whether or not to get the default path using the new method
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to retrieve the path for</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns>String with the path found or NULL if the path is not available</returns>
        private static string GetCommonVistaStyleFolder(KnownCommonFolderType folderType, bool defaultFolder)
        {
            Guid? folderID = GetCommonVistaFolderGuid(folderType);
            StringBuilder builder = new StringBuilder();
            Folders.KnownFolderFlags flags = defaultFolder
                                                 ? Folders.KnownFolderFlags.DefaultPath
                                                 : Folders.KnownFolderFlags.None;

            if (!folderID.HasValue)
            {
                return null;
            }

            uint result = Folders.SHGetKnownFolderPath(folderID.Value, flags, IntPtr.Zero, builder);

            return result == Folders.S_OK ? builder.ToString() : null;
        }

        /// <summary>
        /// Retrieves the folder path knowing a folder type and whether or not to get the default path using the old method
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to retrieve the path for</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns>String with the path found or NULL if the path is not available</returns>
        private static string GetCommonXPStyleFolder(KnownCommonFolderType folderType, bool defaultFolder)
        {
            Folders.SpecialFolderType? folderID = GetCommonXPFolderGuid(folderType);
            StringBuilder builder = new StringBuilder();
            Folders.SpecialFolderFlags flags = defaultFolder
                                                   ? Folders.SpecialFolderFlags.TypeDefault
                                                   : Folders.SpecialFolderFlags.TypeCurrent;

            if (!folderID.HasValue)
            {
                return null;
            }

            uint result = Folders.SHGetFolderPath(IntPtr.Zero, folderID.Value, IntPtr.Zero, flags, builder);

            return result == Folders.S_OK ? builder.ToString() : null;
        }

        #endregion

        #region Common Folder Mappings

        /// <summary>
        /// Gets a Vista Folder Type from a known common folder type
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to convert</param>
        /// <returns>Guid of the known folder or NULL if the type is not found or available</returns>
        private static Guid? GetCommonVistaFolderGuid(KnownCommonFolderType folderType)
        {
            switch (folderType)
            {
                case KnownCommonFolderType.AdminTools:
                    return SystemFolderConstants.CommonAdminTools;

                case KnownCommonFolderType.OEMLinks:
                    return SystemFolderConstants.CommonOEMLinks;

                case KnownCommonFolderType.Programs:
                    return SystemFolderConstants.CommonPrograms;

                case KnownCommonFolderType.StartMenu:
                    return SystemFolderConstants.CommonStartMenu;

                case KnownCommonFolderType.Startup:
                    return SystemFolderConstants.CommonStartup;

                case KnownCommonFolderType.Templates:
                    return SystemFolderConstants.CommonTemplates;

                case KnownCommonFolderType.Fonts:
                    return SystemFolderConstants.Fonts;

                case KnownCommonFolderType.LocalizedResourcesDir:
                    return SystemFolderConstants.LocalizedResourcesDir;

                case KnownCommonFolderType.ProgramData:
                    return SystemFolderConstants.ProgramData;

                case KnownCommonFolderType.ProgramFiles:
                    return SystemFolderConstants.ProgramFiles;

                case KnownCommonFolderType.ProgramFilesCommon:
                    return SystemFolderConstants.ProgramFilesCommon;

                case KnownCommonFolderType.ProgramFilesCommonX64:
                    return SystemFolderConstants.ProgramFilesCommonX64;

                case KnownCommonFolderType.ProgramFilesCommonX86:
                    return SystemFolderConstants.ProgramFilesCommonX86;

                case KnownCommonFolderType.ProgramFilesX64:
                    return SystemFolderConstants.ProgramFilesX64;

                case KnownCommonFolderType.ProgramFilesX86:
                    return SystemFolderConstants.ProgramFilesX86;

                case KnownCommonFolderType.Public:
                    return SystemFolderConstants.Public;

                case KnownCommonFolderType.PublicDesktop:
                    return SystemFolderConstants.PublicDesktop;

                case KnownCommonFolderType.PublicDocuments:
                    return SystemFolderConstants.PublicDocuments;

                case KnownCommonFolderType.PublicDownloads:
                    return SystemFolderConstants.PublicDownloads;

                case KnownCommonFolderType.PublicGameTasks:
                    return SystemFolderConstants.PublicGameTasks;

                case KnownCommonFolderType.PublicMusic:
                    return SystemFolderConstants.PublicMusic;

                case KnownCommonFolderType.PublicPictures:
                    return SystemFolderConstants.PublicPictures;

                case KnownCommonFolderType.PublicVideos:
                    return SystemFolderConstants.PublicVideos;

                case KnownCommonFolderType.ResourceDir:
                    return SystemFolderConstants.ResourceDir;

                case KnownCommonFolderType.SampleMusic:
                    return SystemFolderConstants.SampleMusic;

                case KnownCommonFolderType.SamplePictures:
                    return SystemFolderConstants.SamplePictures;

                case KnownCommonFolderType.SamplePlaylists:
                    return SystemFolderConstants.SamplePlaylists;

                case KnownCommonFolderType.SampleVideos:
                    return SystemFolderConstants.SampleVideos;

                case KnownCommonFolderType.SidebarDefaultParts:
                    return SystemFolderConstants.SidebarDefaultParts;

                case KnownCommonFolderType.System:
                    return SystemFolderConstants.System;

                case KnownCommonFolderType.SystemX86:
                    return SystemFolderConstants.SystemX86;

                case KnownCommonFolderType.UserProfiles:
                    return SystemFolderConstants.UserProfiles;

                case KnownCommonFolderType.Windows:
                    return SystemFolderConstants.Windows;

                default:
                    return null;
            }
        }

        /// <summary>
        /// Gets a XP Folder Type from a known common folder type
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to convert</param>
        /// <returns>Folders.SpecialFolderType of the known folder or NULL if the type is not found or available</returns>
        private static Folders.SpecialFolderType? GetCommonXPFolderGuid(KnownCommonFolderType folderType)
        {
            switch (folderType)
            {
                case KnownCommonFolderType.AdminTools:
                    return Folders.SpecialFolderType.CommonAdministrativeTools;

                case KnownCommonFolderType.OEMLinks:
                    return Folders.SpecialFolderType.CommonOemLinks;

                case KnownCommonFolderType.Programs:
                    return Folders.SpecialFolderType.CommonPrograms;

                case KnownCommonFolderType.StartMenu:
                    return Folders.SpecialFolderType.CommonStartMenu;

                case KnownCommonFolderType.Startup:
                    return Folders.SpecialFolderType.CommonStartup;

                case KnownCommonFolderType.Templates:
                    return Folders.SpecialFolderType.CommonTemplates;

                case KnownCommonFolderType.Fonts:
                    return Folders.SpecialFolderType.Fonts;

                case KnownCommonFolderType.LocalizedResourcesDir:
                    return Folders.SpecialFolderType.LocalizedResources;

                case KnownCommonFolderType.ProgramData:
                    return Folders.SpecialFolderType.CommonAppData;

                case KnownCommonFolderType.ProgramFiles:
                    return Folders.SpecialFolderType.ProgramFiles;

                case KnownCommonFolderType.ProgramFilesCommon:
                    return Folders.SpecialFolderType.CommonProgramFiles;

                case KnownCommonFolderType.ProgramFilesCommonX64:
                    return Folders.SpecialFolderType.CommonProgramFiles;

                case KnownCommonFolderType.ProgramFilesCommonX86:
                    return Folders.SpecialFolderType.CommonProgramFilesX86;

                case KnownCommonFolderType.ProgramFilesX64:
                    return Folders.SpecialFolderType.ProgramFiles;

                case KnownCommonFolderType.ProgramFilesX86:
                    return Folders.SpecialFolderType.ProgramFilesX86;

                case KnownCommonFolderType.PublicDesktop:
                    return Folders.SpecialFolderType.CommonDesktop;

                case KnownCommonFolderType.PublicDocuments:
                    return Folders.SpecialFolderType.CommonDocuments;

                case KnownCommonFolderType.PublicMusic:
                    return Folders.SpecialFolderType.CommonMusic;

                case KnownCommonFolderType.PublicPictures:
                    return Folders.SpecialFolderType.CommonPictures;

                case KnownCommonFolderType.PublicVideos:
                    return Folders.SpecialFolderType.CommonVideo;

                case KnownCommonFolderType.ResourceDir:
                    return Folders.SpecialFolderType.Resources;

                case KnownCommonFolderType.System:
                    return Folders.SpecialFolderType.System;

                case KnownCommonFolderType.SystemX86:
                    return Folders.SpecialFolderType.SystemX86;

                case KnownCommonFolderType.Windows:
                    return Folders.SpecialFolderType.Windows;

                default:
                    return null;
            }
        }

        #endregion

        #region User Folder Calls

        /// <summary>
        /// Retrieves the user folder path knowing a folder type and whether or not to get the default path using the new method
        /// </summary>
        /// <param name="user">User of the folder to retrive</param>
        /// <param name="folderType">KnownCommonFolderType to retrieve the path for</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns>String with the path found or NULL if the path is not available</returns>
        private static string GetUserVistaStyleFolder(WindowsIdentity user, KnownUserFolderType folderType, bool defaultFolder)
        {
            Guid? folderID = GetUserVistaFolderGuid(folderType);
            StringBuilder builder = new StringBuilder();
            Folders.KnownFolderFlags flags = defaultFolder
                                                 ? Folders.KnownFolderFlags.DefaultPath
                                                 : Folders.KnownFolderFlags.None;
            IntPtr userToken = user == null
                                   ? new IntPtr(-1)
                                   : user.Token;

            if (!folderID.HasValue)
            {
                return null;
            }

            uint result = Folders.SHGetKnownFolderPath(folderID.Value, flags, userToken, builder);

            return result == Folders.S_OK ? builder.ToString() : null;
        }

        /// <summary>
        /// Retrieves the user folder path knowing a folder type and whether or not to get the default path using the old method
        /// </summary>
        /// <param name="user">User of the folder to retrive</param>
        /// <param name="folderType">KnownCommonFolderType to retrieve the path for</param>
        /// <param name="defaultFolder">Boolean whether or not to retrieve the default path</param>
        /// <returns>String with the path found or NULL if the path is not available</returns>
        private static string GetUserXPStyleFolder(WindowsIdentity user, KnownUserFolderType folderType, bool defaultFolder)
        {
            Folders.SpecialFolderType? folderID = GetUserXPFolderGuid(folderType);
            StringBuilder builder = new StringBuilder();
            Folders.SpecialFolderFlags flags = defaultFolder
                                                   ? Folders.SpecialFolderFlags.TypeDefault
                                                   : Folders.SpecialFolderFlags.TypeCurrent;
            IntPtr userToken = user == null
                                   ? new IntPtr(-1)
                                   : user.Token;

            if (!folderID.HasValue)
            {
                return null;
            }

            uint result = Folders.SHGetFolderPath(IntPtr.Zero, folderID.Value, userToken, flags, builder);

            return result == Folders.S_OK ? builder.ToString() : null;
        }

        #endregion

        #region User Folder Mappings

        /// <summary>
        /// Gets an User Vista Folder Type from a known common folder type
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to convert</param>
        /// <returns>Guid of the known folder or NULL if the type is not found or available</returns>
        private static Guid? GetUserVistaFolderGuid(KnownUserFolderType folderType)
        {
            switch (folderType)
            {
                case KnownUserFolderType.AdminTools:
                    return UserFolderConstants.AdminTools;

                case KnownUserFolderType.CDBurning:
                    return UserFolderConstants.CDBurning;

                case KnownUserFolderType.Contacts:
                    return UserFolderConstants.Contacts;

                case KnownUserFolderType.Cookies:
                    return UserFolderConstants.Cookies;

                case KnownUserFolderType.Desktop:
                    return UserFolderConstants.Desktop;

                case KnownUserFolderType.Documents:
                    return UserFolderConstants.Documents;

                case KnownUserFolderType.Downloads:
                    return UserFolderConstants.Downloads;

                case KnownUserFolderType.Favorites:
                    return UserFolderConstants.Favorites;

                case KnownUserFolderType.GameTasks:
                    return UserFolderConstants.GameTasks;

                case KnownUserFolderType.History:
                    return UserFolderConstants.History;

                case KnownUserFolderType.InternetCache:
                    return UserFolderConstants.InternetCache;

                case KnownUserFolderType.Links:
                    return UserFolderConstants.Links;

                case KnownUserFolderType.LocalAppData:
                    return UserFolderConstants.LocalAppData;

                case KnownUserFolderType.LocalAppDataLow:
                    return UserFolderConstants.LocalAppDataLow;

                case KnownUserFolderType.Music:
                    return UserFolderConstants.Music;

                case KnownUserFolderType.NetHood:
                    return UserFolderConstants.NetHood;

                case KnownUserFolderType.OriginalImages:
                    return UserFolderConstants.OriginalImages;

                case KnownUserFolderType.PhotoAlbums:
                    return UserFolderConstants.PhotoAlbums;

                case KnownUserFolderType.Pictures:
                    return UserFolderConstants.Pictures;

                case KnownUserFolderType.Playlists:
                    return UserFolderConstants.Playlists;

                case KnownUserFolderType.PrintHood:
                    return UserFolderConstants.PrintHood;
                    
                case KnownUserFolderType.Profile:
                    return UserFolderConstants.Profile;

                case KnownUserFolderType.Programs:
                    return UserFolderConstants.Programs;

                case KnownUserFolderType.QuickLaunch:
                    return UserFolderConstants.QuickLaunch;

                case KnownUserFolderType.Recent:
                    return UserFolderConstants.Recent;

                case KnownUserFolderType.RoamingAppData:
                    return UserFolderConstants.RoamingAppData;

                case KnownUserFolderType.SavedGames:
                    return UserFolderConstants.SavedGames;

                case KnownUserFolderType.SavedSearches:
                    return UserFolderConstants.SavedSearches;

                case KnownUserFolderType.SendTo:
                    return UserFolderConstants.SendTo;

                case KnownUserFolderType.SidebarParts:
                    return UserFolderConstants.SidebarParts;

                case KnownUserFolderType.StartMenu:
                    return UserFolderConstants.StartMenu;

                case KnownUserFolderType.Startup:
                    return UserFolderConstants.Startup;

                case KnownUserFolderType.Templates:
                    return UserFolderConstants.Templates;

                case KnownUserFolderType.Videos:
                    return UserFolderConstants.Videos;

                default:
                    return null;
            }
        }

        /// <summary>
        /// Gets an XP Vista Folder Type from a known common folder type
        /// </summary>
        /// <param name="folderType">KnownCommonFolderType to convert</param>
        /// <returns>Folders.SpecialFolderType of the known folder or NULL if the type is not found or available</returns>
        private static Folders.SpecialFolderType? GetUserXPFolderGuid(KnownUserFolderType folderType)
        {
            switch (folderType)
            {
                case KnownUserFolderType.AdminTools:
                    return Folders.SpecialFolderType.AdministrativeTools;

                case KnownUserFolderType.CDBurning:
                    return Folders.SpecialFolderType.CDBurning;

                case KnownUserFolderType.Cookies:
                    return Folders.SpecialFolderType.Cookies;

                case KnownUserFolderType.Desktop:
                    return Folders.SpecialFolderType.Desktop;

                case KnownUserFolderType.Documents:
                    return Folders.SpecialFolderType.MyDocuments;

                case KnownUserFolderType.Favorites:
                    return Folders.SpecialFolderType.Favorites;

                case KnownUserFolderType.History:
                    return Folders.SpecialFolderType.History;

                case KnownUserFolderType.InternetCache:
                    return Folders.SpecialFolderType.InternetCache;

                case KnownUserFolderType.LocalAppData:
                    return Folders.SpecialFolderType.LocalApplicationData;

                case KnownUserFolderType.Music:
                    return Folders.SpecialFolderType.MyMusic;

                case KnownUserFolderType.NetHood:
                    return Folders.SpecialFolderType.NetHood;

                case KnownUserFolderType.Pictures:
                    return Folders.SpecialFolderType.MyPictures;

                case KnownUserFolderType.PrintHood:
                    return Folders.SpecialFolderType.PrintHood;

                case KnownUserFolderType.Profile:
                    return Folders.SpecialFolderType.Profile;

                case KnownUserFolderType.Programs:
                    return Folders.SpecialFolderType.Programs;

                case KnownUserFolderType.Recent:
                    return Folders.SpecialFolderType.Recent;

                case KnownUserFolderType.SendTo:
                    return Folders.SpecialFolderType.SendTo;

                case KnownUserFolderType.StartMenu:
                    return Folders.SpecialFolderType.StartMenu;

                case KnownUserFolderType.Startup:
                    return Folders.SpecialFolderType.Startup;

                case KnownUserFolderType.Templates:
                    return Folders.SpecialFolderType.Templates;

                case KnownUserFolderType.Videos:
                    return Folders.SpecialFolderType.MyVideo;

                default:
                    return null;
            }
        }

        #endregion
    }
}